            

%{


#include <iostream>
#include "tp.h"

#include <stdio.h>
#include <string.h>
extern "C"
{
        int yyparse(void);
        int yylex(void);  
        int yywrap()
        {
                return 1;
        }
        void analizo_grafo(nodeType *);
        int yyval =  0; 
}


/* prototypes */

nodeType *buildNode(char c, int tipo);
nodeType *joinThreeNodes(nodeType * h1, nodeType * h2, nodeType * h3, int tipo);
nodeType *joinTwoNodes(nodeType * h1, nodeType * h2, int tipo);
nodeType *joinSingleNode(nodeType * h1, int tipo);

void yyerror(const char *str)
{
        fprintf(stderr,"error: %s\n",str);
}
 


%}

%left '/'                      
%left CARACTER
%nonassoc '_' '^'  

%union {
    char iValue;                 /* integer value */
    nodeType *nPtr;             /* node pointer */
};

%type <nPtr> analizar e c f g t
%token <iValue> CARACTER
%token PLACEHOLDER
%% 
inicio: | 
        inicio analizar
        ;
analizar: 
        e PLACEHOLDER
        {
            $$=joinSingleNode($1, RAIZ);
            analizo_grafo($$);
        }
        ;
        
        
        
        
e:
        e '/' f
        {
                $$=joinTwoNodes($1, $3, DIVISION);
                std::cout << "reconozco e/e: "  << std::endl;
        }
        |
        f
        {
                $$=joinSingleNode($1, CONVERSION);
                std::cout << "reconozco f: "  << std::endl;
        }
        ;
 
 
f:
        f g
        {
                $$=joinTwoNodes($1, $2, CONCATENACION);
                std::cout << "reconozco f g: "  << std::endl;
        }
        |
        g
        {
                $$=joinSingleNode($1, CONVERSION);
                std::cout << "reconozco g: "  << std::endl;
        } 
        ;

g:
        t '^' t 
        {
                $$=joinTwoNodes($1, $3, SUPERINDICE);
                std::cout << "reconozco t^t: "  << std::endl;
        }
        |
        t '_' t
        {
                $$=joinTwoNodes($1, $3, SUBINDICE);
                std::cout << "reconozco t_t: "  << std::endl;
        }
        |
        t
        {
                $$=joinSingleNode($1, CONVERSION);
                std::cout << "reconozco t: "  << std::endl;
        }
        ;
        
        
c:        
        CARACTER
        {
                $$=buildNode($1, TERMINAL);
                $$->h2 = 0.0f;
                char temp = $1;
                std::cout << "reconozco caracter: " << temp << std::endl;
        }
        ;
        
        
t:
        '(' e ')' 
        {
                $$=joinSingleNode($2, PARENTESIS);
        }
        |
        '{' e '}'
        {
                $$=joinSingleNode($2, PARENTESIS);
        }
        |
        t '^' t '_' t 
        {
                $$=joinThreeNodes($1, $3, $5, SUPERSUB);
        }
        |
        t '_' t '^' t 
        {
                $$=joinThreeNodes($1, $3, $5, SUBSUPER);
        }
        |
        c 
        {
                $$=joinSingleNode($1, C2CHAR);
        }
        ;

%%


nodeType *buildNode(char c, int tipo) {
    nodeType *p;
    
    p = new nodeType();
    p->caracter = c;
    p->tipo = tipo;
    return p;
}

nodeType * joinSingleNode(nodeType * h1, int tipo) {
    nodeType *p;
    p = buildNode('R', tipo);
    p->hijo1 = (int *)h1;
    h1->padre = (int *) p;
    return p;
}

nodeType *joinTwoNodes(nodeType * h1, nodeType * h2, int tipo) {
    nodeType *p = joinSingleNode(h1, tipo);
    p->hijo2 = (int *)h2;
    return p;
}

nodeType *joinThreeNodes(nodeType * h1, nodeType * h2, nodeType * h3, int tipo) {
    nodeType *p = joinTwoNodes(h1, h2,  tipo);
    p->hijo3 = (int *)h3;
    return p;
}


void yyerror(char *s) {
    fprintf(stdout, "%s\n", s);
}

int main(void) {
    yyparse();
    return 0;
}
float max_float(float x, float y)
{
    if(x > y)
    {
        return x;
    }
    else
    {
        return y;
    }
}

infoSintetizados propagar_escala(nodeType * n)
{
    std::cout << "propagar_escala, tipo: " << n->tipo << std::endl;
    const float cuanto_bajo = 0.6f;
    const float cuanto_subo = cuanto_bajo;
    const float cuanto_subo_division = 0.28f;
    bool ya_entre = false;
    infoSintetizados result;
    if(n->tipo == TERMINAL && !ya_entre)
    {
        ya_entre = true;
        n->h2 = 0;
        n->h1 = n->escala;
        n->ancho = 0.6f;
        result.ancho = 0.6f;
        result.h1 = n->h1;
        result.h2 = n->h2;
    }
    if(n->tipo == CONCATENACION && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        hijo1->escala = n->escala;
        infoSintetizados temp = propagar_escala(hijo1);
        hijo2->escala = n->escala;
        infoSintetizados temp2 = propagar_escala(hijo2);
        result.ancho = temp.ancho + temp2.ancho;
        result.h1 = max_float(temp.h1, temp2.h1);
        result.h2 = max_float(temp.h2, temp2.h2);
    }
    if(n->tipo == SUBINDICE && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        hijo1->escala = n->escala;
        infoSintetizados temp = propagar_escala(hijo1);
        hijo2->escala = n->escala * 0.7f;
        infoSintetizados temp2 = propagar_escala(hijo2);
        result.ancho = temp.ancho + temp2.ancho;
        result.h1 = max_float(temp.h1, temp2.h1 - cuanto_bajo * n->escala)  ;
        result.h2 = max_float(temp.h2, temp2.h2 + cuanto_bajo * n->escala);
        
    }
    if(n->tipo == SUPERINDICE && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        hijo1->escala = n->escala;
        infoSintetizados temp = propagar_escala(hijo1);
        hijo2->escala = n->escala * 0.7f;
        infoSintetizados temp2 = propagar_escala(hijo2);
        result.ancho = temp.ancho + temp2.ancho;
        result.h1 = max_float(temp.h1, temp2.h1 + cuanto_subo * n->escala);
        result.h2 =  max_float(temp.h2, temp2.h2 - cuanto_subo * n->escala)  ;
    }
    if(n->tipo == DIVISION && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        hijo1->escala = n->escala;
        infoSintetizados temp = propagar_escala(hijo1);
        hijo2->escala = n->escala;
        infoSintetizados temp2 = propagar_escala(hijo2);
        result.ancho = max_float(temp.ancho, temp2.ancho);
        result.h1 = temp.h1 + temp.h2 + cuanto_subo_division + 0.1 *n->escala;
        result.h2 =  temp2.h1 + temp2.h2 - cuanto_subo_division + 0.1 *n->escala;
        
        
    }
    if(n->tipo == PARENTESIS && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        
        hijo1->escala = n->escala;
        infoSintetizados temp = propagar_escala(hijo1);
        
        result.ancho = temp.ancho + 1.2f;
        result.h1 = temp.h1;
        result.h2 = temp.h2;
    }
    if(n->tipo == SUBSUPER && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        nodeType * hijo3 = ((nodeType *) n->hijo3);
        
        hijo1->escala = n->escala;
        infoSintetizados temp = propagar_escala(hijo1);
        
        
        hijo2->escala = n->escala * 0.7f;
        infoSintetizados temp2 = propagar_escala(hijo2);
        
        
        
        hijo3->escala = n->escala * 0.7f;
        infoSintetizados temp3 = propagar_escala(hijo3);
        
        result.ancho = temp.ancho + max_float(temp2.ancho, temp3.ancho);
        result.h1 = max_float( temp.h1, temp3.h1 + (cuanto_subo * n->escala));
        result.h2 = max_float( temp.h2, temp2.h2 + (cuanto_bajo * n->escala));
        
        
    }
    if(n->tipo == SUPERSUB && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        nodeType * hijo3 = ((nodeType *) n->hijo3);
        
        hijo1->escala = n->escala;
        infoSintetizados temp = propagar_escala(hijo1);
        
        
        hijo2->escala = n->escala * 0.7f;
        infoSintetizados temp2 = propagar_escala(hijo2);
        
        
        
        hijo3->escala = n->escala * 0.7f;
        infoSintetizados temp3 = propagar_escala(hijo3);
        
        result.ancho = temp.ancho + max_float(temp2.ancho, temp3.ancho);
        result.h1 = max_float( temp.h1, temp2.h1 + (cuanto_subo * n->escala));
        result.h2 = max_float( temp.h2, temp3.h2 + (cuanto_bajo * n->escala));
    }
    if(( n->tipo == C2CHAR ||n->tipo == RAIZ || n->tipo == CONVERSION) && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        nodeType * hijo3 = ((nodeType *) n->hijo3);
        
        hijo1->escala = n->escala;
        result = propagar_escala(hijo1);
        n->ancho = result.ancho;
        n->h1 = result.h1;
        n->h2 = result.h2;
        
    }
    if(!ya_entre)
    {
        std::cout << "PROBLEMON: el tipo del nodo es cualquier cosa!!" << std::endl;
    }
    n->h1 = result.h1;
    n->h2 = result.h2;
    n->ancho = result.ancho;
    return result;
}
float y_adjust;
void propagar_heredados(nodeType * n)
{
    std::cout << "propagar_heredados, tipo: " << n->tipo << " ancho: " << n->ancho << std::endl;
    const float cuanto_bajo = 0.6f;
    const float cuanto_subo = cuanto_bajo;
    const float cuanto_subo_division = 0.28f;
    bool ya_entre = false;
    if(n->tipo == TERMINAL && !ya_entre)
    {
        std::cout << "caracter: " <<  n->caracter<<", ancho:  " << n->ancho << std::endl;
        std::cout << "caracter: " <<  n->caracter<<", y:  " << n->x << std::endl;
        ya_entre = true;
        std::cerr.precision(2);
        std::cerr << "gsave ";
        std::cerr << n->x << " " << n->y << " moveto ";
        std::cerr << n->escala << " " << n->escala;
        std::cerr << " scale (" << n->caracter << ") show grestore"   << std::endl;
    }
    if(n->tipo == CONCATENACION && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        hijo1->x = n->x;
        hijo1->y = n->y;
        propagar_heredados(hijo1);
        hijo2->x = n->x + hijo1->ancho;
        hijo2->y = n->y;
        propagar_heredados(hijo2);
    }
    if(n->tipo == SUBINDICE && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        hijo1->x = n->x;
        hijo1->y = n->y;
        propagar_heredados(hijo1);
        
        hijo2->x = n->x + hijo1->ancho;
        hijo2->y = n->y - cuanto_bajo * n->escala; // Ver cuanto hace falta bajarlo
        propagar_heredados(hijo2);
        
        
    }
    if(n->tipo == SUPERINDICE && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        hijo1->x = n->x;
        hijo1->y = n->y;
        propagar_heredados(hijo1);
        
        hijo2->x = n->x + hijo1->ancho;
        hijo2->y = n->y + cuanto_subo * n->escala; // Ver cuanto hace falta subirlo
        propagar_heredados(hijo2);
        
    }
    if(n->tipo == DIVISION && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        hijo1->x = n->x;
        hijo1->y = n->y + cuanto_subo_division * n->escala +  0.1 *n->escala;
        propagar_heredados(hijo1);
        
        hijo2->x = n->x;
        hijo2->y = n->y - ( hijo2->h2) * n->escala + cuanto_subo_division * n->escala - 0.1 *n->escala; // Ver cuanto hace falta bajarlo
        propagar_heredados(hijo2);
        
        
        std::cerr.precision(2);
        std::cerr << "gsave ";
        std::cerr << n->x << " " << (n->y + cuanto_subo_division) << " moveto ";
        std::cerr << n->ancho << " " << 0.0f;
        std::cerr << " rlineto stroke grestore"   << std::endl;
    }
    if(n->tipo == PARENTESIS && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        hijo1->x = n->x + 0.6f;
        hijo1->y = n->y ;
        propagar_heredados(hijo1);
    }
    if(n->tipo == SUBSUPER && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        nodeType * hijo3 = ((nodeType *) n->hijo3);
        hijo1->x = n->x;
        hijo1->y = n->y;
        propagar_heredados(hijo1);
        
        hijo2->x = n->x + hijo1->ancho;
        hijo2->y = n->y - cuanto_bajo * n->escala; // Ver cuanto hace falta bajarlo
        propagar_heredados(hijo2);
        
        
        hijo3->x = n->x + hijo1->ancho;
        hijo3->y = n->y + cuanto_subo * n->escala; // Ver cuanto hace falta subirlo
        propagar_heredados(hijo3);
    }
    if(n->tipo == SUPERSUB && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        nodeType * hijo2 = ((nodeType *) n->hijo2);
        nodeType * hijo3 = ((nodeType *) n->hijo3);
        hijo1->x = n->x;
        hijo1->y = n->y;
        propagar_heredados(hijo1);
        
        
        hijo2->x = n->x + hijo1->ancho;
        hijo2->y = n->y + cuanto_subo * n->escala; // Ver cuanto hace falta subirlo
        propagar_heredados(hijo2);
        
        hijo3->x = n->x + hijo1->ancho;
        hijo3->y = n->y - cuanto_bajo * n->escala; // Ver cuanto hace falta bajarlo
        propagar_heredados(hijo3);
        
        
    }
    if((n->tipo == C2CHAR || n->tipo == RAIZ || n->tipo == CONVERSION) && !ya_entre)
    {
        ya_entre = true;
        nodeType * hijo1 = ((nodeType *) n->hijo1);
        hijo1->x = n->x;
        hijo1->y = n->y;
        propagar_heredados(hijo1);
    }

    if(n->tipo == C2CHAR && !ya_entre)
    {
        ya_entre = true;
    }
    if(!ya_entre)
    {
        std::cout << "PROBLEMON: el tipo del nodo es cualquier cosa!!" << std::endl;
    }
}
void analizo_grafo(nodeType * n) 
{
    if(n->tipo != RAIZ)
    {
        std::cout << "PROBLEMON: la raiz no es raiz!!!" << std::endl;
    }
    
    n->escala=1.0f;
    propagar_escala(n);
    std::cerr << "%!PS-Adobe-3.0 EPSF-3.0" << std::endl;
    std::cerr << "%%BoundingBox: 0 0 " << (int(n->ancho) + 1) *12 << " "<< (1+int(n->h1 + n->h2)) *12<< std::endl;
    std::cerr << "1 " << int(n->h1) + 1<< " translate" << std::endl;
    std::cerr << "12 12 scale" << std::endl;
    std::cerr << ".03 setlinewidth" << std::endl;
    std::cerr << "/Courier findfont setfont" << std::endl;
    n->x = 0;
    n->y = n->h2;
    propagar_heredados(n);
    std::cout << "la rompo en yacc" << std::endl;
}   


// (A^BC^D/E^F_G+H)-I
